import tkinter as tk
from tkinter import ttk, scrolledtext, filedialog, messagebox
import ttkbootstrap as ttkb
from ttkbootstrap.constants import *
from ttkbootstrap.dialogs import Messagebox
import pandas as pd
import os
from datetime import datetime
import configparser
import tempfile
import subprocess
from tinydb import TinyDB, Query, where
from tinydb.storages import JSONStorage
from tinydb.middlewares import CachingMiddleware

from app.util.annotation_util import annotate, ClassInfo
from app.view.base_view import View

@annotate(ClassInfo(name="FtAuSnPrint", category="ft_tool"))
class FtAuSnPrintView(View):
    """设置视图"""

    def __init__(self, parent, controller):
        super().__init__(parent, controller)
        # 配置文件设置
        self.config = configparser.ConfigParser()
        self.config_file = "config/barcode_config.ini"
        self.load_config()

        # 数据存储 - 使用TinyDB替代SQLite
        self.db = TinyDB(
            "config/barcode_records.json",
            storage=CachingMiddleware(JSONStorage)
        )
        self.printed_table = self.db.table("printed_records")

        # 数据存储
        self.current_batch = []
        self.batch_size = int(self.config.get("Settings", "batch_size", fallback=10))
        self.auto_print = self.config.getboolean("Settings", "auto_print", fallback=False)
        self.excel_template = self.config.get("Settings", "excel_template", fallback="")
        self.save_path = self.config.get("Settings", "save_path", fallback=os.path.expanduser("~"))

        # 创建UI
        self._create_widgets()

        # 日志记录
        self.log("程序已启动")

    def load_config(self):
        """加载配置文件"""
        if os.path.exists(self.config_file):
            self.config.read(self.config_file)
        else:
            # 创建默认配置
            self.config["Settings"] = {
                "batch_size": "10",
                "auto_print": "False",
                "excel_template": "",
                "save_path": os.path.expanduser("~")
            }
            with open(self.config_file, "w") as f:
                self.config.write(f)

    def save_config(self):
        """保存配置到文件"""
        self.config["Settings"]["batch_size"] = str(self.batch_size)
        self.config["Settings"]["auto_print"] = str(self.auto_print)
        self.config["Settings"]["excel_template"] = self.excel_template
        self.config["Settings"]["save_path"] = self.save_path

        with open(self.config_file, "w") as f:
            self.config.write(f)

    def _create_widgets(self):
        """创建UI组件"""
        # 主框架
        main_frame = ttk.Frame(self, padding=10)
        main_frame.pack(fill=BOTH, expand=YES)

        # 顶部设置区域
        settings_frame = ttk.LabelFrame(main_frame, text="设置", padding=10)
        settings_frame.pack(fill=X, pady=(0, 10))

        # 批次大小设置
        ttk.Label(settings_frame, text="批次数量:").grid(row=0, column=0, padx=5, pady=5, sticky=W)
        self.batch_size_var = tk.StringVar(value=str(self.batch_size))
        batch_size_entry = ttk.Entry(settings_frame, textvariable=self.batch_size_var, width=10)
        batch_size_entry.grid(row=0, column=1, padx=5, pady=5)
        ttk.Button(
            settings_frame,
            text="应用",
            command=lambda: self.set_batch_size(),
            bootstyle=PRIMARY
        ).grid(row=0, column=2, padx=5, pady=5)

        # 自动打印开关
        self.auto_print_var = tk.BooleanVar(value=self.auto_print)
        auto_print_check = ttk.Checkbutton(
            settings_frame,
            text="自动打印",
            variable=self.auto_print_var,
            command=self.toggle_auto_print
        )
        auto_print_check.grid(row=0, column=3, padx=20, pady=5, sticky=W)

        # Excel模板设置
        ttk.Label(settings_frame, text="Excel模板:").grid(row=0, column=4, padx=5, pady=5, sticky=W)
        self.template_path_var = tk.StringVar(value=self.excel_template)
        ttk.Entry(settings_frame, textvariable=self.template_path_var, width=30).grid(
            row=0, column=5, padx=5, pady=5
        )
        ttk.Button(
            settings_frame,
            text="浏览",
            command=self.select_template,
            bootstyle=SECONDARY
        ).grid(row=0, column=6, padx=5, pady=5)

        # 保存路径设置
        ttk.Label(settings_frame, text="保存路径:").grid(row=0, column=7, padx=5, pady=5, sticky=W)
        self.save_path_var = tk.StringVar(value=self.save_path)
        ttk.Entry(settings_frame, textvariable=self.save_path_var, width=30).grid(
            row=0, column=8, padx=5, pady=5
        )
        ttk.Button(
            settings_frame,
            text="浏览",
            command=self.select_save_path,
            bootstyle=SECONDARY
        ).grid(row=0, column=9, padx=5, pady=5)

        # 中间主要操作区域
        mid_frame = ttk.Frame(main_frame)
        mid_frame.pack(fill=BOTH, expand=YES, pady=(0, 10))

        # 左侧扫码区域
        scan_frame = ttk.LabelFrame(mid_frame, text="扫码区域", padding=10)
        scan_frame.pack(side=LEFT, fill=BOTH, expand=YES, padx=(0, 10))

        # 设备条码
        ttk.Label(scan_frame, text="设备条码 (SN):", font=("Helvetica", 10, "bold")).pack(anchor=W, pady=(10, 2))
        self.device_barcode_var = tk.StringVar()
        device_entry = ttk.Entry(
            scan_frame,
            textvariable=self.device_barcode_var,
            font=("Helvetica", 14),
            bootstyle=INFO
        )
        device_entry.pack(fill=X, pady=(0, 10), ipady=5)
        device_entry.focus_set()

        # 外盒条码
        ttk.Label(scan_frame, text="外盒条码 (SN):", font=("Helvetica", 10, "bold")).pack(anchor=W, pady=(10, 2))
        self.box_barcode_var = tk.StringVar()
        box_entry = ttk.Entry(
            scan_frame,
            textvariable=self.box_barcode_var,
            font=("Helvetica", 14),
            bootstyle=INFO
        )
        box_entry.pack(fill=X, pady=(0, 10), ipady=5)

        # 比对结果
        self.compare_result_var = tk.StringVar(value="等待扫码...")
        self.compare_label = ttk.Label(
            scan_frame,
            textvariable=self.compare_result_var,
            font=("Helvetica", 12, "bold"),
            padding=10
        )
        self.compare_label.pack(fill=X, pady=10)

        # 操作按钮
        buttons_frame = ttk.Frame(scan_frame)
        buttons_frame.pack(fill=X, pady=20)

        ttk.Button(
            buttons_frame,
            text="比对并记录",
            command=self.compare_and_record,
            bootstyle=SUCCESS,
            width=15
        ).pack(side=LEFT, padx=10)

        ttk.Button(
            buttons_frame,
            text="手动添加",
            command=self.manual_add,
            bootstyle=INFO,
            width=15
        ).pack(side=LEFT, padx=10)

        ttk.Button(
            buttons_frame,
            text="清空当前批次",
            command=self.clear_current_batch,
            bootstyle=WARNING,
            width=15
        ).pack(side=LEFT, padx=10)

        ttk.Button(
            buttons_frame,
            text="生成Excel",
            command=self.generate_excel,
            bootstyle=PRIMARY,
            width=15
        ).pack(side=LEFT, padx=10)

        # 右侧当前批次和记录查看区域
        right_frame = ttk.Frame(mid_frame)
        right_frame.pack(side=RIGHT, fill=BOTH, expand=YES)

        # 标签页
        self.notebook = ttk.Notebook(right_frame)
        self.notebook.pack(fill=BOTH, expand=YES)

        # 当前批次标签页
        current_batch_tab = ttk.Frame(self.notebook)
        self.notebook.add(current_batch_tab, text="当前批次")

        # 当前批次列表
        columns = ("index", "sn", "time")
        self.batch_tree = ttk.Treeview(
            current_batch_tab,
            columns=columns,
            show="headings",
            selectmode="browse"
        )

        self.batch_tree.heading("index", text="序号")
        self.batch_tree.heading("sn", text="SN条码")
        self.batch_tree.heading("time", text="扫描时间")

        self.batch_tree.column("index", width=60, anchor=CENTER)
        self.batch_tree.column("sn", width=200)
        self.batch_tree.column("time", width=150)

        # 添加滚动条
        batch_scrollbar = ttk.Scrollbar(
            current_batch_tab,
            orient=VERTICAL,
            command=self.batch_tree.yview
        )
        self.batch_tree.configure(yscroll=batch_scrollbar.set)

        batch_scrollbar.pack(side=RIGHT, fill=Y)
        self.batch_tree.pack(fill=BOTH, expand=YES, padx=5, pady=5)

        # 已打印记录标签页
        printed_tab = ttk.Frame(self.notebook)
        self.notebook.add(printed_tab, text="已打印记录")

        # 已打印记录列表
        print_columns = ("id", "sn", "print_time", "batch_id")
        self.printed_tree = ttk.Treeview(
            printed_tab,
            columns=print_columns,
            show="headings",
            selectmode="browse"
        )

        self.printed_tree.heading("id", text="ID")
        self.printed_tree.heading("sn", text="SN条码")
        self.printed_tree.heading("print_time", text="打印时间")
        self.printed_tree.heading("batch_id", text="批次ID")

        self.printed_tree.column("id", width=60, anchor=CENTER)
        self.printed_tree.column("sn", width=200)
        self.printed_tree.column("print_time", width=150)
        self.printed_tree.column("batch_id", width=100)

        # 添加滚动条
        print_scrollbar = ttk.Scrollbar(
            printed_tab,
            orient=VERTICAL,
            command=self.printed_tree.yview
        )
        self.printed_tree.configure(yscroll=print_scrollbar.set)

        print_scrollbar.pack(side=RIGHT, fill=Y)
        self.printed_tree.pack(fill=BOTH, expand=YES, padx=5, pady=5)

        # 加载已打印记录
        self.load_printed_records()

        # 汇总标签页
        summary_tab = ttk.Frame(self.notebook)
        self.notebook.add(summary_tab, text="汇总统计")

        # 汇总信息
        self.summary_text = scrolledtext.ScrolledText(
            summary_tab,
            wrap=tk.WORD,
            state=DISABLED
        )
        self.summary_text.pack(fill=BOTH, expand=YES, padx=5, pady=5)

        # 更新汇总信息
        self.update_summary()

        # 底部日志区域
        log_frame = ttk.LabelFrame(main_frame, text="操作日志", padding=10)
        log_frame.pack(fill=BOTH, expand=YES)

        self.log_text = scrolledtext.ScrolledText(
            log_frame,
            wrap=tk.WORD,
            state=DISABLED,
            height=8
        )
        self.log_text.pack(fill=BOTH, expand=YES)

        # 绑定事件
        self.device_barcode_var.trace_add("write", self.auto_focus_box)
        self.box_barcode_var.trace_add("write", self.auto_verify)

        # 绑定回车键触发比对
        device_entry.bind("<Return>", lambda e: box_entry.focus_set())
        box_entry.bind("<Return>", lambda e: self.compare_and_record())

    def log(self, message):
        """添加日志信息"""
        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        log_message = f"[{timestamp}] {message}\n"

        self.log_text.config(state=NORMAL)
        self.log_text.insert(END, log_message)
        self.log_text.see(END)
        self.log_text.config(state=DISABLED)

    def set_batch_size(self):
        """设置批次大小"""
        try:
            new_size = int(self.batch_size_var.get())
            if new_size > 0:
                self.batch_size = new_size
                self.save_config()
                self.log(f"批次大小已设置为: {self.batch_size}")
                Messagebox.show_info(f"批次大小已设置为: {self.batch_size}")
            else:
                Messagebox.show_error("批次大小必须大于0")
                self.batch_size_var.set(str(self.batch_size))
        except ValueError:
            Messagebox.show_error("请输入有效的数字")
            self.batch_size_var.set(str(self.batch_size))

    def toggle_auto_print(self):
        """切换自动打印状态"""
        self.auto_print = self.auto_print_var.get()
        self.save_config()
        status = "开启" if self.auto_print else "关闭"
        self.log(f"自动打印已{status}")

    def select_template(self):
        """选择Excel模板文件"""
        file_path = filedialog.askopenfilename(
            title="选择Excel模板",
            filetypes=[("Excel files", "*.xlsx;*.xls")]
        )
        if file_path:
            self.excel_template = file_path
            self.template_path_var.set(file_path)
            self.save_config()
            self.log(f"已选择Excel模板: {file_path}")

    def select_save_path(self):
        """选择保存路径"""
        path = filedialog.askdirectory(title="选择保存路径")
        if path:
            self.save_path = path
            self.save_path_var.set(path)
            self.save_config()
            self.log(f"已选择保存路径: {path}")

    def auto_focus_box(self, *args):
        """当设备条码有输入时自动聚焦到外盒条码"""
        if self.device_barcode_var.get() and not self.box_barcode_var.get():
            # 这里使用after确保UI更新完成
            self.after(100, lambda: self.nametowidget(".!frame.!frame.!labelframe.!frame.!entry2").focus_set())

    def auto_verify(self, *args):
        """当外盒条码输入完成时自动进行比对"""
        if self.device_barcode_var.get() and self.box_barcode_var.get():
            # 短暂延迟后自动比对，给扫码枪完成输入的时间
            self.after(500, self.compare_and_record)

    def compare_and_record(self):
        """比对设备条码和外盒条码，如果一致则记录"""
        device_sn = self.device_barcode_var.get().strip()
        box_sn = self.box_barcode_var.get().strip()

        if not device_sn or not box_sn:
            self.compare_result_var.set("请扫描完整的条码")
            self.compare_label.configure(foreground="orange")
            return

        if device_sn == box_sn:
            # 条码一致，记录
            self.current_batch.append({
                "sn": device_sn,
                "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            })

            self.compare_result_var.set(f"条码一致，已记录 (当前: {len(self.current_batch)}/{self.batch_size})")
            self.compare_label.configure(foreground="green")
            self.log(f"记录条码: {device_sn} (当前批次: {len(self.current_batch)}/{self.batch_size})")

            # 更新当前批次列表
            self.update_batch_list()

            # 清空输入框，准备下一次扫描
            self.device_barcode_var.set("")
            self.box_barcode_var.set("")
            self.nametowidget(".!frame.!frame.!labelframe.!frame.!entry").focus_set()

            # 检查是否达到批次大小
            if len(self.current_batch) >= self.batch_size:
                self.log(f"已达到批次大小 {self.batch_size}，准备生成Excel")
                self.generate_excel()

        else:
            # 条码不一致
            self.compare_result_var.set("条码不一致，请重新扫描")
            self.compare_label.configure(foreground="red")
            self.log(f"条码比对失败: 设备SN={device_sn}, 外盒SN={box_sn}")

    def manual_add(self):
        """手动添加SN条码"""
        manual_window = ttk.Toplevel(self)
        manual_window.title("手动添加SN")
        manual_window.geometry("400x200")
        manual_window.transient(self)
        manual_window.grab_set()
        manual_window.resizable(False, False)

        ttk.Label(manual_window, text="请输入SN条码:", font=("Helvetica", 10, "bold")).pack(anchor=W, padx=20,
                                                                                            pady=(20, 5))

        sn_var = tk.StringVar()
        sn_entry = ttk.Entry(manual_window, textvariable=sn_var, font=("Helvetica", 12), width=30)
        sn_entry.pack(padx=20, pady=(0, 20), ipady=3)
        sn_entry.focus_set()

        def confirm_add():
            sn = sn_var.get().strip()
            if sn:
                self.current_batch.append({
                    "sn": sn,
                    "time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                })

                self.update_batch_list()
                self.log(f"手动添加条码: {sn} (当前批次: {len(self.current_batch)}/{self.batch_size})")
                manual_window.destroy()

                # 检查是否达到批次大小
                if len(self.current_batch) >= self.batch_size:
                    self.log(f"已达到批次大小 {self.batch_size}，准备生成Excel")
                    self.generate_excel()
            else:
                Messagebox.show_warning("输入错误", "请输入有效的SN条码")

        button_frame = ttk.Frame(manual_window)
        button_frame.pack(fill=X, padx=20, pady=10)

        ttk.Button(
            button_frame,
            text="确认添加",
            command=confirm_add,
            bootstyle=SUCCESS
        ).pack(side=LEFT, padx=10)

        ttk.Button(
            button_frame,
            text="取消",
            command=manual_window.destroy,
            bootstyle=DANGER
        ).pack(side=RIGHT, padx=10)

        sn_entry.bind("<Return>", lambda e: confirm_add())

    def update_batch_list(self):
        """更新当前批次列表"""
        # 清空现有内容
        for item in self.batch_tree.get_children():
            self.batch_tree.delete(item)

        # 添加当前批次的所有条码
        for i, item in enumerate(self.current_batch, 1):
            self.batch_tree.insert("", END, values=(i, item["sn"], item["time"]))

    def clear_current_batch(self):
        """清空当前批次"""
        if self.current_batch:
            if Messagebox.show_question("确认", "确定要清空当前批次吗?") == "yes":
                self.current_batch.clear()
                self.update_batch_list()
                self.log("当前批次已清空")
        else:
            Messagebox.show_info("提示", "当前批次为空")

    def generate_excel(self):
        """生成Excel文件"""
        if not self.current_batch:
            Messagebox.show_info("提示", "当前批次为空，无法生成Excel")
            return

        if not self.excel_template or not os.path.exists(self.excel_template):
            if Messagebox.show_question("模板不存在", "未找到Excel模板，是否继续使用空白模板?") != "yes":
                return

        try:
            # 创建批次ID
            batch_id = datetime.now().strftime("%Y%m%d%H%M%S")

            # 生成文件名
            filename = f"barcode_batch_{batch_id}.xlsx"
            save_path = os.path.join(self.save_path, filename)

            # 读取模板或创建新文件
            if self.excel_template and os.path.exists(self.excel_template):
                df = pd.read_excel(self.excel_template)
                self.log(f"使用模板生成Excel: {self.excel_template}")
            else:
                # 创建空白模板
                df = pd.DataFrame(columns=["序号", "SN条码", "扫描时间"])
                self.log("使用空白模板生成Excel")

            # 将SN填入指定位置（这里假设模板中的"SN条码"列是目标列）
            # 实际应用中可能需要根据模板结构调整
            for i, item in enumerate(self.current_batch, 1):
                # 检查是否有"SN条码"列
                if "SN条码" in df.columns:
                    # 找到第一个空行
                    empty_row = df[df["SN条码"].isna()].index.min() if not df[df["SN条码"].isna()].empty else len(df)
                    df.at[empty_row, "SN条码"] = item["sn"]
                    if "序号" in df.columns:
                        df.at[empty_row, "序号"] = i
                    if "扫描时间" in df.columns:
                        df.at[empty_row, "扫描时间"] = item["time"]
                else:
                    # 如果没有"SN条码"列，添加新行
                    df.loc[len(df)] = [i, item["sn"], item["time"]]

            # 保存Excel文件
            df.to_excel(save_path, index=False)
            self.log(f"Excel文件已生成: {save_path}")
            Messagebox.show_info("成功", f"Excel文件已生成:\n{save_path}")

            # 记录到数据库
            self.save_to_database(batch_id)

            # 如果开启自动打印，进行打印
            if self.auto_print:
                self.print_excel(save_path, batch_id)
            else:
                # 询问是否打印
                if Messagebox.show_question("打印", "是否要打印生成的Excel文件?") == "yes":
                    self.print_excel(save_path, batch_id)

            # 清空当前批次
            self.current_batch.clear()
            self.update_batch_list()

        except Exception as e:
            self.log(f"生成Excel失败: {str(e)}")
            Messagebox.show_error("错误", f"生成Excel失败:\n{str(e)}")

    def save_to_database(self, batch_id):
        """将当前批次的SN保存到TinyDB"""
        try:
            print_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            records = []
            for item in self.current_batch:
                records.append({
                    "sn": item["sn"],
                    "print_time": print_time,
                    "batch_id": batch_id
                })

            # 插入多条记录
            self.printed_table.insert_multiple(records)
            # 提交更改（由于使用了CachingMiddleware）
            self.db.storage.flush()

            self.log(f"已将 {len(self.current_batch)} 条记录保存到数据库")

            # 更新已打印记录和汇总信息
            self.load_printed_records()
            self.update_summary()

        except Exception as e:
            self.log(f"保存记录到数据库失败: {str(e)}")
            Messagebox.show_error("错误", f"保存记录失败:\n{str(e)}")

    def load_printed_records(self):
        """加载已打印的记录"""
        try:
            # 清空现有内容
            for item in self.printed_tree.get_children():
                self.printed_tree.delete(item)

            # 查询数据库，按打印时间降序排列，取最近100条
            records = self.printed_table.all()
            # 按打印时间排序
            records.sort(key=lambda x: x["print_time"], reverse=True)
            # 只取最近100条
            recent_records = records[:100]

            # 添加到表格
            for i, record in enumerate(recent_records, 1):
                # TinyDB没有自增ID，这里使用索引作为ID显示
                self.printed_tree.insert(
                    "",
                    END,
                    values=(i, record["sn"], record["print_time"], record["batch_id"])
                )

        except Exception as e:
            self.log(f"加载已打印记录失败: {str(e)}")

    def update_summary(self):
        """更新汇总统计信息"""
        try:
            # 获取所有记录
            all_records = self.printed_table.all()
            total = len(all_records)

            # 计算今日记录数
            today = datetime.now().strftime("%Y-%m-%d")
            today_count = 0
            for record in all_records:
                if record["print_time"].startswith(today):
                    today_count += 1

            # 计算批次数量（去重）
            batch_ids = set(record["batch_id"] for record in all_records)
            batch_count = len(batch_ids)

            # 统计最近10个批次
            batch_stats = {}
            for record in all_records:
                batch_id = record["batch_id"]
                if batch_id not in batch_stats:
                    batch_stats[batch_id] = {
                        "count": 1,
                        "time": record["print_time"]
                    }
                else:
                    batch_stats[batch_id]["count"] += 1

            # 按时间排序批次
            sorted_batches = sorted(
                batch_stats.items(),
                key=lambda x: x[1]["time"],
                reverse=True
            )[:10]

            # 生成汇总文本
            summary = f"总打印记录: {total} 条\n"
            summary += f"今日打印记录: {today_count} 条\n"
            summary += f"总批次数量: {batch_count} 个\n\n"
            summary += "最近10个批次:\n"

            for batch_id, stats in sorted_batches:
                summary += f"  批次 {batch_id}: {stats['count']} 条记录\n"

            # 更新文本框
            self.summary_text.config(state=NORMAL)
            self.summary_text.delete(1.0, END)
            self.summary_text.insert(END, summary)
            self.summary_text.config(state=DISABLED)

        except Exception as e:
            self.log(f"更新汇总信息失败: {str(e)}")

    def print_excel(self, file_path, batch_id):
        """打印Excel文件"""
        try:
            self.log(f"准备打印文件: {file_path}")

            # 使用系统默认程序打开并打印
            if os.name == 'nt':  # Windows系统
                # 使用PowerShell命令打印
                subprocess.run(['powershell', 'Start-Process', '-FilePath', file_path, '-Verb', 'Print'], check=True)
            else:  # Linux或macOS
                # 使用lp命令打印
                subprocess.run(['lp', file_path], check=True)

            self.log(f"文件已发送到打印机: {file_path}")
            Messagebox.show_info("打印", "文件已发送到打印机，请在打印预览中确认打印")

        except Exception as e:
            self.log(f"打印文件失败: {str(e)}")
            Messagebox.show_error("打印失败", f"打印文件时出错:\n{str(e)}")

    def destroy(self):
        """关闭窗口时确保数据库正确关闭"""
        self.db.close()
        super().destroy()

    def create_widgets(self):
        pass
